package com.yikome.shop.api;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.stripe.Stripe;
import com.stripe.model.Charge;
import com.stripe.net.RequestOptions;
import com.yikome.order.entity.Order;
import com.yikome.order.enums.OrderStatus;
import com.yikome.promotion.response.ShopFullReductionResponse;
import com.yikome.promotion.service.FullReductionService;
import com.yikome.shop.api.dto.CartPriceDTO;
import com.yikome.shop.api.dto.CollectionApiDTO;
import com.yikome.shop.api.dto.FeedBackCreateRequest;
import com.yikome.shop.api.dto.OrderQueryDTO;
import com.yikome.shop.api.dto.ProductApiDTO;
import com.yikome.shop.api.dto.ShopApiDTO;
import com.yikome.shop.entity.Shop;
import com.yikome.shop.request.SubmitCartRequest;
import com.yikome.shop.service.ShopService;
import com.yikome.shop.utils.ExchangeRateUtils;
import com.yikome.utils.NetworkUtils;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * shop前端API接口问题:
 */

@Slf4j
@RestController
@RequestMapping("/api/shop")
public class ShopApi {

	@Autowired
	private ShopService shopService ; 
	
	@Autowired
	private FullReductionService fullReductionService ; 
	
	@Value("${stripe.dataKey}")
	private String stripeDataKey ; 
	@Value("${stripe.apiKey}")
	private String stripeApiKey;
	
	@GetMapping("/full-reduction")
	public List<ShopFullReductionResponse> findShopFullReductionResponse(HttpServletRequest request){
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Preconditions.checkArgument(shop != null, "Sorry for the mistake on the website...");
		
		return fullReductionService.findShopFullReductionResponse(shop.getId());
	}
	
	/**
	 * 根据域名返回商城信息,这里包含的是商城及其导航分类信息
	 */
	@GetMapping("/name")
	public Map<String , Object> findShopName(HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Preconditions.checkArgument(shop != null, "Sorry for the mistake on the website...");
		
		Preconditions.checkArgument(StrUtil.isNotBlank(shop.getCurrency()), "Sorry for the mistake on the website...");
		
		List<ShopFullReductionResponse> fullReductions = fullReductionService.findShopFullReductionResponse(shop.getId());
		
		Map<String, Object> paramMaps = new HashMap<>();
		paramMaps.put("domainName", shop.getName());
		paramMaps.put("logo" , shop.getLogo());
		paramMaps.put("currencySymbol" , shop.getCurrencySymbol());
		paramMaps.put("currencuy" , shop.getCurrency());
		paramMaps.put("freight" , shop.getFreight());
		paramMaps.put("basicPrice" , shop.getBasicPrice());
		paramMaps.put("country" , shop.getCountry());
		
		paramMaps.put("fbPiexId" , shop.getFbPiexId());
		paramMaps.put("fbMessageId" , shop.getFbMessageId());
		
		paramMaps.put("addressBase" , shop.getAddressBase());
		paramMaps.put("languageBase" , shop.getLanguageBase());
		
		paramMaps.put("fullReduction", fullReductions);
		
		return paramMaps ; 
	}
	
	@GetMapping("/other")
	public Map<String , Object> findShopOther(HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Preconditions.checkArgument(shop != null, "Sorry for the mistake on the website...");
		
		return ImmutableMap.of("aboutUs", shop.getAboutUs(), "privacyPolicy" , shop.getPrivacyPolicy(), "exchangePolicy" , shop.getExchangePolicy(), "problems" , shop.getProblems());
	}
	
	@GetMapping
	public ShopApiDTO findShop(HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Preconditions.checkArgument(shop != null, "Sorry for the mistake on the website...");
		
		return shopService.findShop(shop) ; 
		
	}
	
	/**
	 * 根据导航ID返回导航下所有的聚合信息
	 */
	@GetMapping("/collections")
	public List<CollectionApiDTO> findNavCollections(HttpServletRequest request){
		
		String navIdString = request.getParameter("navId");
		
		String anavIdString = request.getParameter("anavId");
		
		log.info("findNavCollections [" + navIdString + "] start : " + LocalDateTime.now());
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Preconditions.checkArgument(StrUtil.isNotBlank(navIdString), "Sorry for the mistake on the website...");
		
		List<CollectionApiDTO> collectionApiDTOs = new ArrayList<>();
		
		if(StrUtil.isNotBlank(anavIdString)) {
			List<String> anavIds = StrUtil.split(anavIdString, '~');
			for (String anavId : anavIds) {
				CollectionApiDTO collectionApiDTO = shopService.findCollection(Convert.toLong(anavId, 0L));
				if(collectionApiDTO != null) collectionApiDTOs.add(collectionApiDTO);
			}
		}
		
		List<String> navIds = StrUtil.split(navIdString, '~');
		
		collectionApiDTOs.addAll(shopService.findNavCollections(navIds));
		
		collectionApiDTOs = ExchangeRateUtils.filterCollectionApiDTO(collectionApiDTOs, shop.getExchangeRate());
		
		log.info("findNavCollections [" + navIdString + "] end : " + LocalDateTime.now());
		
		return collectionApiDTOs ; 
	}
	
	@GetMapping("/product/{productId}")
	public ProductApiDTO findProduct(@PathVariable("productId") Long productId , HttpServletRequest request){
		
		log.info("findProduct [" + productId + "] start : " + LocalDateTime.now());
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		ProductApiDTO productApiDTO = shopService.findProduct(productId);
		
		productApiDTO.setSimilarProduct(shopService.findBottomProduct(productId));
		productApiDTO.setLikeProduct(shopService.findLikeProduct(productId));
		productApiDTO.setProductComments(shopService.findProductComments(productId));
		
		//TODO
		productApiDTO.setProductSets(shopService.findProductSets(productId));
		
		productApiDTO = ExchangeRateUtils.filterProductApiDTO(productApiDTO, shop.getExchangeRate());
		
		Preconditions.checkArgument(productApiDTO != null, "Sorry for the mistake on the website...");
		
		log.info("findProduct [" + productId + "] end : " + LocalDateTime.now());
		
		return productApiDTO ; 
	}
	
	@PostMapping("/cart/calculation")
	public CartPriceDTO caculateCartPrice(HttpServletRequest request , @RequestBody SubmitCartRequest submitCartRequest) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		CartPriceDTO cartPriceDTO = shopService.caculateCartPrice(submitCartRequest, shop);
		
		return cartPriceDTO ; 
	}
	
	@PostMapping("/cart/submit")
	public Map<String , Object> submitCart(HttpServletRequest request , @RequestBody SubmitCartRequest submitCartRequest) {
		
		Preconditions.checkArgument(submitCartRequest.getCartProductRequests() != null && submitCartRequest.getCartProductRequests().size() > 0, "還沒有選擇商品...");
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Order order = shopService.submitCart(submitCartRequest, shop, NetworkUtils.getIpAddress(request), Boolean.TRUE);
		
		return ImmutableMap.of("orderCode", order.getCode());
	}
	
	@GetMapping("/stripe/key")
	public Map<String , Object> stripeKey(HttpServletRequest request){
		return ImmutableMap.of("stripeDataKey" , stripeDataKey);
	}
	
	@PostMapping("/stripe/checkout")
	public Map<String , Object> stripeCheckout(HttpServletRequest request, @RequestBody SubmitCartRequest submitCartRequest){
		
		Preconditions.checkArgument(submitCartRequest.getCartProductRequests() != null && submitCartRequest.getCartProductRequests().size() > 0, "還沒有選擇商品...");
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Order order = shopService.stripeSubmitCart(submitCartRequest, shop, NetworkUtils.getIpAddress(request));
		
		Stripe.apiKey = stripeApiKey;
		
		Preconditions.checkArgument(StrUtil.isNotBlank(submitCartRequest.getStripeToken()), "信用卡參數缺失...");
		
        Preconditions.checkArgument(order != null, "訂單信息不存在...");
        Preconditions.checkArgument(order.getStatus() == OrderStatus.ORDER_PAY.getStatus(), "訂單信息不存在...");

        Map<String, Object> params = new HashMap<String, Object>();
        params.put("amount", order.getPrice().multiply(BigDecimal.valueOf(0.995)).multiply(BigDecimal.valueOf(100)).toBigInteger());
        params.put("currency", order.getCurrency().toLowerCase());
        params.put("description", order.getCode());
        params.put("source", submitCartRequest.getStripeToken());

        RequestOptions options = RequestOptions.builder().setIdempotencyKey("ORDER-CODE-" + order.getCode()).build();

        Map<String, String> initialMetadata = new HashMap<String, String>();
        initialMetadata.put("orderId", String.valueOf(order.getId()));
        initialMetadata.put("orderCode", order.getCode());
        params.put("metadata", initialMetadata);
        
        try {
            Charge charge = Charge.create(params, options);
            if (StrUtil.equalsIgnoreCase(charge.getStatus(), "succeeded")) {
            	shopService.successStripe(order);
            }
        } catch (Exception e) {
        	e.printStackTrace();
            throw new RuntimeException("支付失敗...");
        }
        return ImmutableMap.of("orderCode", order.getCode());
	}
	
	@GetMapping("/order/{querys}")
	public OrderQueryDTO findUserOrder(@PathVariable("querys") String querys , HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		return shopService.findUserOrder(querys , shop);
		
	}
	
	@GetMapping("/recomend/hots")
	public List<ProductApiDTO> findRecomendHosts(HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		List<ProductApiDTO> recomendHosts = shopService.findRecomendHosts(shop);
		
		return ExchangeRateUtils.filterRecomendHosts(recomendHosts, shop.getExchangeRate());
		
	}
	
	@GetMapping("/keywords")
	public List<String> findShopKeywords(HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));

		return shopService.findShopKeywords(shop);
		
	}
	
	@GetMapping("/search/{keyword}")
	public Object findSearchProduct(@PathVariable("keyword") String keywords, @PageableDefault(sort = {"default"}, size = 100, direction = Sort.Direction.DESC) Pageable pageable, HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		
		Long convertProductId = Convert.toLong(keywords, -1L);
		if(convertProductId.intValue() > 0) {
			Boolean exsitProduct = shopService.exsitProductId(convertProductId);
			if(exsitProduct) return Boolean.TRUE ;
		}
		
		List<ProductApiDTO> searchProducts = shopService.findSearchProduct(keywords , pageable);
		
		if(searchProducts != null && !searchProducts.isEmpty()) {
			return ExchangeRateUtils.filterRecomendHosts(searchProducts, shop.getExchangeRate());
		}
		
		List<ProductApiDTO> recomendHosts = shopService.findRecomendHosts(shop);
		
		return ExchangeRateUtils.filterRecomendHosts(recomendHosts, shop.getExchangeRate());
		
	}
	
	@PostMapping("/feedBack")
	public Boolean createFeedBack(@RequestBody FeedBackCreateRequest feedBackCreateRequest, HttpServletRequest request) {
		
		Shop shop = shopService.getRequestShop(request.getHeader("requestHost"));
		Preconditions.checkArgument(shop != null, "shop is invalid");
		
		feedBackCreateRequest.setShopId(shop.getId());
		
		Preconditions.checkArgument(StrUtil.isNotBlank(feedBackCreateRequest.getTel()), "tel is empty");
		Preconditions.checkArgument(StrUtil.isNotBlank(feedBackCreateRequest.getText()), "feedback is empty");
		
		shopService.createFeedBack(feedBackCreateRequest);
		
		return Boolean.TRUE ;
	}
	
}
